﻿using System;
using System.Collections.Generic;
using DiffPlex.DiffBuilder.Model;
using DiffPlex.Model;

namespace DiffPlex.DiffBuilder
{
    public class InlineDiffBuilder : IInlineDiffBuilder
    {
        private readonly IDiffer differ;

        public InlineDiffBuilder(IDiffer differ)
        {
            this.differ = differ ?? throw new ArgumentNullException(nameof(differ));
        }

        

        public DiffPaneModel BuildDiffModel(string oldText, string newText)
        {
            if (oldText == null) throw new ArgumentNullException(nameof(oldText));
            if (newText == null) throw new ArgumentNullException(nameof(newText));

            var model = new DiffPaneModel();



            // var diffResult = differ.CreateLineDiffs(oldText, newText, ignoreWhitespace: true);

            var diffResult2 = differ.CreateCharacterDiffs(oldText, newText, ignoreWhitespace: true);
            
          BuildDiffPieces(diffResult2, model.Lines);
            //BuildDiffPieces(diffResult2, model.Lines);

            
            return model;
        }

        /// <summary>
        /// 自建模型，返回结果类的数组
        /// </summary>
        /// <param name="oldText"></param>
        /// <param name="newText"></param>
        /// <returns></returns>
        public List<Result> IIBuildDiffModel(string oldText, string newText)
        {
            if (oldText == null) throw new ArgumentNullException(nameof(oldText));
            if (newText == null) throw new ArgumentNullException(nameof(newText));

            var model = new DiffPaneModel();

            var diffResult = differ.CreateCharacterDiffs(oldText, newText, ignoreWhitespace: true);
            List<Result> resultList = new List<Result>();

            IIBuildString(diffResult, resultList);

            return resultList;
        }

        /// <summary>
        /// 根据diffResult把结果信息类存到list数组
        /// </summary>
        /// <param name="diffResult"></param>
        /// <param name="resultList"></param>
        private static void IIBuildString(DiffResult diffResult, List<Result> resultList)
        {
            foreach (var diffBlock in diffResult.DiffBlocks)
            {

                if ((diffBlock.DeleteCountA != 0) && (diffBlock.InsertCountB != 0))
                {
                    string oldS = ConvertArray2StringFrom(diffResult.PiecesOld, diffBlock.DeleteStartA, diffBlock.DeleteCountA);
                    string newS = ConvertArray2StringFrom(diffResult.PiecesNew, diffBlock.InsertStartB, diffBlock.InsertCountB);
                    string content = "\"" + oldS + "\"" + "\"" + newS + "\"";

                    Result result = new Result(diffBlock.DeleteStartA, diffBlock.DeleteCountA, diffBlock.InsertStartB, diffBlock.InsertCountB, "修改", content);
                    resultList.Add(result);

                }
                else if (diffBlock.DeleteCountA > diffBlock.InsertCountB)
                {
                    string oldS = ConvertArray2StringFrom(diffResult.PiecesOld, diffBlock.DeleteStartA, diffBlock.DeleteCountA);
                    string content = oldS;

                    Result result = new Result(diffBlock.DeleteStartA, diffBlock.DeleteCountA, 0, 0, "删除", content);
                    resultList.Add(result);

                }
                else
                {
                    string newS = ConvertArray2StringFrom(diffResult.PiecesNew, diffBlock.InsertStartB, diffBlock.InsertCountB);
                    string content = newS;
                    Result result = new Result(0, 0, diffBlock.InsertStartB, diffBlock.InsertCountB, "新增", content);
                    resultList.Add(result);
                }
            }

        }//private

        /// <summary>
        /// 从string数组截取string
        /// </summary>
        /// <param name="strA"></param>
        /// <param name="startIndex"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static string ConvertArray2StringFrom(string[] strA, int startIndex, int count)
        {
            string result = "";
            for (int i = 0; i < count; i++)
            {
                result += strA[startIndex];
                startIndex++;
            }
            return result;
        }

        private static void BuildDiffPieces(DiffResult diffResult, List<DiffPiece> pieces)
        {
            int bPos = 0;

            foreach (var diffBlock in diffResult.DiffBlocks)
            {
                for (; bPos < diffBlock.InsertStartB; bPos++)
                    pieces.Add(new DiffPiece(diffResult.PiecesNew[bPos], ChangeType.Unchanged, bPos + 1));

                int i = 0;
                for (; i < Math.Min(diffBlock.DeleteCountA, diffBlock.InsertCountB); i++)
                    pieces.Add(new DiffPiece(diffResult.PiecesOld[i + diffBlock.DeleteStartA], ChangeType.Deleted));

                i = 0;
                for (; i < Math.Min(diffBlock.DeleteCountA, diffBlock.InsertCountB); i++)
                {
                    pieces.Add(new DiffPiece(diffResult.PiecesNew[i + diffBlock.InsertStartB], ChangeType.Inserted, bPos + 1));
                    bPos++;
                }

                if (diffBlock.DeleteCountA > diffBlock.InsertCountB)
                {
                    for (; i < diffBlock.DeleteCountA; i++)
                        pieces.Add(new DiffPiece(diffResult.PiecesOld[i + diffBlock.DeleteStartA], ChangeType.Deleted));
                }
                else
                {
                    for (; i < diffBlock.InsertCountB; i++)
                    {
                        pieces.Add(new DiffPiece(diffResult.PiecesNew[i + diffBlock.InsertStartB], ChangeType.Inserted, bPos + 1));
                        bPos++;
                    }
                }
            }

            for (; bPos < diffResult.PiecesNew.Length; bPos++)
                pieces.Add(new DiffPiece(diffResult.PiecesNew[bPos], ChangeType.Unchanged, bPos + 1));
        }
    }
}
